<?php

class UpsComponent extends Component {



    const LIVE_URL = 'https://www.ups.com/ups.app/xml/Rate';
    const TEST_URL = 'https://wwwcie.ups.com/ups.app/xml/Rate';

    private $url;
    public $defaults = array(
        'ShipperZip' => '94901',
        'ShipperCountry' => 'US',
        'ShipFromZip' => '94901',
        'ShipFromCountry' => 'US',
        'ShipToZip' => '',
        'ShipToCountry' => 'US',
        'ShipperNumber' => '01',
        'PickupType' => '01',
        'PackagingType' => '02',
        'DimensionsUnit' => 'IN',
        'DimensionsLength' => '8',
        'DimensionsHeight' => '8',
        'DimensionsWidth' => '8',
        'WeightUnit' => 'LBS',
        'Weight' => '1',
        'Service' => '03'
    );



    public function startup(Controller $controller, $options = array()) {

        if (Configure::read('Settings.UPS_MODE') == 'test') {
            $this->url = self::TEST_URL;
        } else if (Configure::read('Settings.UPS_MODE') == 'live') {
            $this->url = self::LIVE_URL;
        }

        $this->defaults = array_merge((array) $this->defaults, (array) $options);
    }



    public function getRate($data = null) {

        if ($data['Weight'] < .1) {
            $data['Weight'] = .1;
        }

        if ($data['Weight'] > 70) {
            $data['Weight'] = 70;
        }

        $xml = $this->buildRequest($data);

        App::uses('HttpSocket', 'Network/Http');
        $httpSocket = new HttpSocket();
        $res = $httpSocket->post($this->url, $xml);

        App::uses('Xml', 'Utility');
        $response = Xml::toArray(Xml::build($res['body']));
        $formattedResponse = $this->formatResponse($response);

        if (!empty($formattedResponse)) {
            return $formattedResponse;
        }
        return false;
    }



    protected function buildRequest($data = array()) {

        $this->defaults = array_merge((array) $this->defaults, (array) $data);

        if ($this->defaults['DimensionsLength'] < .1) {
            $this->defaults['DimensionsLength'] = 1;
        }
        if ($this->defaults['DimensionsHeight'] < .1) {
            $this->defaults['DimensionsHeight'] = 1;
        }
        if ($this->defaults['DimensionsWidth'] < .1) {
            $this->defaults['DimensionsWidth'] = 1;
        }

        $xml = '<?xml version="1.0"?>
		<AccessRequest xml:lang="en-US">
			<AccessLicenseNumber>' . Configure::read('Settings.UPS_ACCESSKEY') . '</AccessLicenseNumber>
			<UserId>' . Configure::read('Settings.UPS_USERID') . '</UserId>
			<Password>' . Configure::read('Settings.UPS_PASSWORD') . '</Password>
		</AccessRequest>
		<?xml version="1.0"?>
		<RatingServiceSelectionRequest xml:lang="en-US">
			<Request>
				<TransactionReference>
					<CustomerContext>Bare Bones Rate Request</CustomerContext>
					<XpciVersion>1.0001</XpciVersion>
				</TransactionReference>
				<RequestAction>Rate</RequestAction>
				<RequestOption>shop</RequestOption>
			</Request>
			<PickupType>
				<Code>' . $this->defaults['PickupType'] . '</Code>
			</PickupType>
			<Shipment>
				<Shipper>
					<Address>
						<PostalCode>' . $this->defaults['ShipperZip'] . '</PostalCode>
						<CountryCode>' . $this->defaults['ShipperCountry'] . '</CountryCode>
					</Address>
					<ShipperNumber>' . $this->defaults['ShipperNumber'] . '</ShipperNumber>
				</Shipper>
				<ShipTo>
					<Address>
						<PostalCode>' . $this->defaults['ShipToZip'] . '</PostalCode>
						<CountryCode>' . $this->defaults['ShipToCountry'] . '</CountryCode>
						<ResidentialAddressIndicator/>
					</Address>
				</ShipTo>
				<ShipFrom>
					<Address>
						<PostalCode>' . $this->defaults['ShipFromZip'] . '</PostalCode>
						<CountryCode>' . $this->defaults['ShipFromCountry'] . '</CountryCode>
					</Address>
				</ShipFrom>
				<Package>
					<PackagingType>
						<Code>' . $this->defaults['PackagingType'] . '</Code>
					</PackagingType>
					<Dimensions>
						<UnitOfMeasurement>
							<Code>' . $this->defaults['DimensionsUnit'] . '</Code>
						</UnitOfMeasurement>
						<Length>' . $this->defaults['DimensionsLength'] . '</Length>
						<Width>' . $this->defaults['DimensionsWidth'] . '</Width>
						<Height>' . $this->defaults['DimensionsHeight'] . '</Height>
					</Dimensions>
					<PackageWeight>
						<UnitOfMeasurement>
							<Code>' . $this->defaults['WeightUnit'] . '</Code>
						</UnitOfMeasurement>
						<Weight>' . number_format($this->defaults['Weight'], 2, '.', '') . '</Weight>
					</PackageWeight>
				</Package>
			</Shipment>
		</RatingServiceSelectionRequest>';

        return $xml;
    }



    protected function formatResponse($response) {

        $service_code = array(
            '01' => 'UPS Next Day Air',
            '02' => 'UPS 2nd Day Air',
            '03' => 'UPS Ground',
            '07' => 'UPS Worldwide Express',
            '08' => 'UPS Worldwide Expedited',
            '11' => 'UPS Standard',
            '12' => 'UPS 3 Day Select',
            '13' => 'UPS Next Day Air Saver',
            '14' => 'UPS Next Day Air Early A.M.',
            '54' => 'UPS Worldwide Express Plus',
            '59' => 'UPS 2nd Day Air A.M.',
        );

        $service_enabled = array(
            '01',
            '02',
            '12',
            '03',
        );

        $results = array();
        $i = 0;

        foreach ($response['RatingServiceSelectionResponse']['RatedShipment'] as $result) {
            $code = $result['Service']['Code'];
            if (in_array($code, $service_enabled)) {
                $results[$i]['ServiceCode'] = $code;
                $results[$i]['ServiceName'] = $service_code[$code];
                $results[$i]['TotalCharges'] = $result['TotalCharges']['MonetaryValue'];
                $i++;
            }
        }

        $results = Hash::sort($results, '{n}.TotalCharges', 'ASC');

        return $results;
    }


}
